home *** CD-ROM | disk | FTP | other *** search
File List | 1989-12-13 | 20.7 KB | 885 lines |
- _C LIST MANAGER_
- by Robert Starr
-
-
- [LISTING ONE]
-
- /* makelist- list management package
- RF Starr
- 2639 Valley Field Dr.
- SugarLand, TX 77479
- */
-
- #include <stdio.h>
- #include <varargs.h>
- #ifdef MSDOS
- #include <stdlib.h>
- #include <malloc.h>
- #else
- #define void char
- extern char *malloc();
- #endif
-
- /*#define DEBUG*/
-
- #ifdef DEBUG
- #define Debug(x) x
- #else
- #define Debug(x)
- #endif
-
- typedef struct data DATA;
- typedef struct list LIST;
- typedef struct prop PROP;
-
- struct data {
- void *data; /* space for list->nentries instances of data */
- DATA *next; /* next list->nentries collection of data */
- };
-
- struct prop {
- void *dataptr; /* to what data item this property associates */
- void *propval; /* property value to associate with the data */
- void *propsym; /* optional symbol (usually char *) to associate */
- PROP *next;
- };
-
- struct list {
- int entrysize; /* size of each data entry in bytes */
- int nentries; /* # entries to grab per malloc call */
- int empty_slots; /* empty slots left in current data block */
- int nitems; /* total items saved in this list */
- int ecount; /* where we are when reading back list */
- int fblock;
- DATA *fdata;
- PROP *prop; /* optional property list for this list */
- DATA *data; /* linked list for the actual data of this list */
- DATA *hidata; /* highest allocated data block (for efficiency) */
- };
-
- /* Internal malloc routine */
- /*#define MEMCHK*/
- #ifdef MEMCHK
- static FILE *memfp = NULL;
- #endif
- static void *
- imalloc(size)
- int size; {
- void *ptr = malloc(size);
- #ifdef MEMCHK
- if (!memfp) memfp = fopen("meminfo","w");
- #endif
- if (!ptr) {
- fprintf(stderr,"malloc error: no free memory left.\n");
- fflush(stderr);
- }
- #ifdef MEMCHK
- fprintf(memfp,"%x malloc\n",ptr);
- fflush(memfp);
- #endif
- return ptr;
- }
-
- static void *
- ifree(addr)
- void *addr; {
- free(addr);
- #ifdef MEMCHK
- fprintf(memfp,"%x free\n",addr);
- fflush(memfp);
- #endif
- }
-
- /* Build, initialize, and return an empty list */
- void *
- makelist(esize,nentries)
- int esize,nentries; {
- LIST *list = imalloc(sizeof(LIST)+sizeof(DATA)+esize*nentries);
- void *dp = imalloc(sizeof(DATA)+esize*nentries);
- if (!list || !dp) return NULL;
- list->data = (DATA *)dp;
- list->data->data = (char *)dp + sizeof(DATA);
- list->entrysize = esize;
- list->nentries = nentries;
- list->empty_slots = nentries;
- list->nitems = 0;
- list->ecount = 0;
- list->fblock = 0;
- list->fdata = NULL;
- list->prop = (PROP *)NULL;
- list->hidata = list->data;
- list->data->next = NULL;
- return (void *)list;
- }
-
- /* Put items on property list for this data item. Propsym is the
- property symbol, and val is a pointer to a _static_ are where the
- data for this property resides.
- */
- putproplist(list,dataptr,propsym,val)
- LIST *list;
- void *dataptr,*val;
- char *propsym; {
- PROP *newprop = (PROP *)imalloc(sizeof(PROP));
- PROP *topprop = list->prop;
- if (!list) return NULL;
- if (!newprop) return;
- newprop->dataptr = dataptr;
- newprop->propsym = propsym;
- newprop->propval = val;
- newprop->next = topprop;
- list->prop = newprop;
- }
-
- /* Read an item off of the property list for a particular data
- item. NULL returned if there is none.
- */
- void *
- getproplist(list,dataptr,propsym)
- LIST *list;
- void *dataptr,*propsym; {
- PROP *p;
- void *propval = NULL;
- if (!list) return NULL;
- p = list->prop;
- while (p) {
- int fsym = !strcmp(p->propsym,propsym);
- if ((!dataptr && fsym) || (p->dataptr == dataptr && fsym)) {
- propval = p->propval;
- break;
- }
- p = p->next;
- }
- return propval;
- }
-
- /* Find data item associated with a property name */
- void *
- findprop(list,propsym)
- LIST *list;
- char *propsym; {
- PROP *p;
- if (!list) return NULL;
- p = list->prop;
- while (p) {
- if (!strcmp(p->propsym,propsym)) return p->dataptr;
- p = p->next;
- }
- return NULL;
- }
-
- /* Append data to the specified list */
- static void
- whereis(list,ndx,walk,put)
- LIST *list;
- int *walk,*put; {
- *walk = ndx / list->nentries;
- *put = ndx % list->nentries;
- }
-
- /* Remove last entry on the specified list... adjust struct accordingly */
- void *
- poplist(list)
- LIST *list; {
- DATA *org;
- void *dp = NULL;
- unsigned char *data;
- int put;
- if (!list) return NULL;
- if (!list->nitems) return dp;
- org = list->data;
- list->empty_slots++;
- list->nitems--;
- if (list->empty_slots == list->nentries) {
- while (org->next) org = org->next;
- put = list->nitems % list->nentries;
- data = (unsigned char *)org->data;
- dp = (void *)(data+(list->entrysize*put));
- if (org->next) ifree(org->next), org->next = NULL;
- list->hidata = org;
- }
- return dp;
- }
-
- /* calculate data pointer for the ndx entry */
- static void *
- calcdp(list,ndx)
- LIST *list;
- int ndx; {
- DATA *pdata;
- unsigned char *dp;
- int size = (list) ? list->entrysize :0;
- int max = (list) ? list->nitems : 0;
- int walk,put;
- if (!list || ndx >= max) return (void *)NULL;
- whereis(list,ndx,&walk,&put);
- pdata = list->data;
- while (walk--) pdata = pdata->next;
- dp = (unsigned char *)pdata->data;
- return (char *)(dp+(size*put));
- }
-
- /* Return pointer to data which is last on the list */
- void *
- toplist(list)
- LIST *list; {
- void *dp = NULL;
- void *fetchlist();
- unsigned char *data;
- int put;
- if (!list || !list->nitems) return NULL;
- return calcdp(list,list->nitems-1);
- }
-
- /* append a data item onto specified list */
- void *
- appendlist(list,data)
- LIST *list;
- void *data; {
- DATA *pdata;
- void *where;
- unsigned char *dp;
- int walk,put,size;
- if (!list) return NULL;
- size = list->entrysize;
- whereis(list,list->nitems,&walk,&put);
- pdata = list->hidata;
- if (!list->empty_slots) {
- void *mem = imalloc(sizeof(DATA)+size*list->nentries);
- if (!mem) return NULL;
- list->hidata = pdata = pdata->next = (DATA *)mem;
- pdata->data = (void *)((char *)mem+sizeof(DATA));
- pdata->next = NULL;
- list->empty_slots = list->nentries;
- }
- dp = (unsigned char *)pdata->data;
- where = (char *)(dp+(put*size));
- memcpy(where,data,size);
- list->empty_slots--;
- list->nitems++;
- return where;
- }
-
- /* return index of NEXT list entry */
- listindex(list)
- LIST *list; {
- return list->nitems;
- }
-
- /* append a data item onto specified list with property value information */
- void *
- pappendlist(list,data,propsym,val)
- LIST *list;
- void *data,*val;
- char *propsym; {
- void *dataptr = appendlist(list,data);
- if (dataptr) putproplist(list,dataptr,propsym,val);
- return dataptr;
- }
-
- /* Just like appendlist... new name for compatibility with poplist */
- void *
- pushlist(list,data)
- LIST *list;
- void *data; {
- if (!list) return NULL;
- return appendlist(list,data);
- }
-
- /* Fetch a specific data item off of list... ndx is 0-based */
- void *
- fetchlist(list,ndx)
- LIST *list;
- int ndx; {
- DATA *pdata;
- unsigned char *dp;
- int size = list->entrysize;
- int max = list->nitems;
- int walk,put;
- if (!list) return NULL;
- if (ndx >= max) return (void *)NULL;
- whereis(list,ndx,&walk,&put);
- if (walk == list->fblock)
- list->fdata = pdata = (list->fdata) ? list->fdata : list->data;
- else {
- pdata = list->data;
- list->fblock = walk;
- while (walk--)
- pdata = pdata->next;
- list->fdata = pdata;
- }
- dp = (unsigned char *)pdata->data;
- Debug(printf("fetchlist: getting data from %x\n",dp+(size*put)));
- return (char *)(dp+(size*put));
- }
-
- /* reset pointer used by walklist */
- rewindlist(list)
- LIST *list; {
- if (list) list->ecount = 0;
- }
-
- /* walk down the list, returning each data item 'till there ain't no more */
- void *
- walklist(list)
- LIST *list; {
- DATA *pdata;
- unsigned char *dp;
- int size = list->entrysize;
- int max = list->nitems;
- int index = list->ecount;
- int walk,put;
- if (!list) return NULL;
- dp = (unsigned char *)fetchlist(list,index);
- if (!dp)
- list->ecount = 0;
- else
- list->ecount++;
- return (list->ecount) ? (void *)dp : (void *)NULL;
- }
-
- /* malloc size bytes, and add address of malloced space to the list */
- void *
- malloclist(list,size)
- LIST *list;
- int size; {
- void *dp;
- if (!list) return NULL;
- dp = imalloc(size);
- if (dp) appendlist(list,&dp);
- return dp;
- }
-
- /* Free up all malloced data associated with the specified list */
- freelist(list)
- LIST *list; {
- fl(list,0);
- }
-
- /* garbage collect list... assume all data in list is malloced ptrs */
- gclist(list)
- LIST *list; {
- fl(list,1);
- }
-
- /* Free the list up. If freedp != 0, free each data pointer as well */
- static
- fl(list,freedp)
- LIST *list; {
- DATA *pdata,*ppd;
- PROP *p = list->prop;
- if (!list) return;
- pdata = list->data;
- if (freedp) {
- void *dp;
- rewindlist(list);
- while (dp=walklist(list))
- ifree(*(char **)dp);
- }
- /* free all malloced data */
- while (pdata) {
- DATA *next = pdata->next;
- ifree(pdata);
- pdata = next;
- }
- /* free all malloced property info */
- while (p) {
- PROP *n = p->next;
- ifree(p);
- p = n;
- }
- ifree(list);
- }
-
- /* given a list of functions, invoke the function with the specified
- property tag with the arguments supplied.
- */
-
- /*funclist(list,prop,args) (actual calling argument list)*/
- int
- funclist(va_alist)
- va_dcl {
- void *list;
- void *prop;
- void *vp;
- int (*func)();
- va_list argmark;
- va_start(argmark);
- list = va_arg(argmark,void *);
- prop = va_arg(argmark,void *);
- vp = findprop(list,prop);
- if (!vp) return 0;
- func = *(int (**)())vp;
- return (*func)(argmark);
- }
-
-
- [LISTING TWO]
-
- /* Header file for makelist */
-
- /* Remove this if you don't have ANSI C compiler */
- #define ANSIC
-
- #ifndef ANSIC
- #define void char
- #endif
-
- /* Usage: e.g. deref(int,x) or deref(char *,x) */
- #define deref(type,x) *((type*)(x))
-
- /* Function prototypes/declarations */
- /*----------------------------------------------------------------------*/
- #ifdef ANSIC
- extern void *makelist(int esize,int nentries);
- extern int putproplist(void *list,void *dataptr,char *propsym,void *val);
- extern void *getproplist(void *list,void *dataptr,void *propsym);
- extern void *toplist(void *list);
- extern void *poplist(void *list);
- extern void *appendlist(void *list,void *data);
- extern void *pappendlist(void *list,void *data,char *propsym,char *val);
- extern void *pushlist(void *list,void *data);
- extern void *fetchlist(void *list,int ndx);
- extern void *walklist(void *list);
- extern void rewindlist(void *list);
- extern void *malloclist(void *list,int size);
- extern int freelist(void *list);
- extern int gclist(void *list);
- extern int funclist(void *,...);
- extern int listindex(void *list);
- #else
- extern void *makelist();
- extern int putproplist();
- extern void *getproplist();
- extern void *toplist();
- extern void *poplist();
- extern void *appendlist();
- extern void *pappendlist();
- extern void *pushlist();
- extern void *fetchlist();
- extern void *walklist();
- extern void rewindlist();
- extern void *malloclist();
- extern int freelist();
- extern int gclist();
- extern int funclist();
- extern int listindex();
- #endif
- /*----------------------------------------------------------------------*/
-
-
- Example 1: A list of integers
-
-
- #ifdef Explanation
- ----------------------------------------------------------------------
- Make a list to hold integers, and put 100 integers onto the list.
- Then, play back the list.
- ----------------------------------------------------------------------
- #endif
-
- #include <stdio.h>
- #include "makelist.h"
-
- main() {
- void *list,*dp;
- int ii;
- /* make a list to hold integers */
- list = makelist(sizeof(int),10);
- /* put 100 integers on list */
- for (ii=0 ; ii < 100 ; ii++)
- appendlist(list,&ii);
- /* use fetchlist to read back list */
- for (ii=0 ; ii < 100 ; ii++) {
- void *dp = fetchlist(list,ii);
- printf("Entry %2d = %d\n",ii,*(int *)dp);
- }
- freelist(list);
- }
-
-
- Example 2: A list of strings
-
-
- #ifdef Explanation
- ----------------------------------------------------------------------
- Demonstrates the putting of strings on a list and use of gclist.
- ----------------------------------------------------------------------
- #endif
-
- #include <stdio.h>
- #include "makelist.h"
-
- extern char *strdup();
-
- main() {
- char buffer[132];
- void *list,*dp,*ptr;
- int ii;
- int cnt;
- /* make list to hold strings */
- list = makelist(sizeof(char *),10);
- /* build the list of strings */
- for (ii=0 ; ii < 30 ; ii++) {
- sprintf(buffer,"text string %d",ii);
- dp = strdup(buffer);
- appendlist(list,&dp);
- }
- /* use walklist to view each string saved in list */
- while (dp = walklist(list))
- printf("%s\n",*((char **)dp));
- /* free up list, as well as all malloced data */
- gclist(list);
- }
-
-
- Example 3: A list of structures
-
-
- #ifdef Explanation
- ----------------------------------------------------------------------
- Saving and retrieving structures on lists.
- ----------------------------------------------------------------------
- #endif
-
- #include <stdio.h>
- #include "makelist.h"
-
- extern char *strdup();
- /* here is our data structure */
- struct foo {
- char *name;
- int ndx;
- } foo;
-
- main() {
- void *list;
- void *vp;
- struct foo *fp;
- int ii,jj,kk;
- char buffer[256];
- /* make list to hold struct foo */
- list = makelist(sizeof(struct foo),10);
- /* build list of 30 instances of struct foo */
- for (ii=0 ; ii < 30 ; ii++) {
- sprintf(buffer,"foo element %d",ii);
- foo.name = strdup(buffer);
- foo.ndx = ii;
- appendlist(list,&foo);
- }
- /* play back list. note that vp is merely cast */
- while (vp=walklist(list)) {
- fp = (struct foo *)vp;
- printf("%2d) %s\n",fp->ndx,fp->name);
- }
- /* free up each string malloced during list creation */
- while (vp=walklist(list)) {
- fp = (struct foo *)vp;
- free(fp->name);
- }
- /* free the list itself */
- freelist(list);
- }
-
-
- Example 4: Using malloclist()
-
- #ifdef Explanation
- ----------------------------------------------------------------------
- We use malloclist to get memory space, rather than malloc. This will
- automatically append malloced data onto a list (which you must provide),
- so that a single call to gclist will free not only the list, but all
- malloced space as well.
- ----------------------------------------------------------------------
- #endif
-
- #include <stdio.h>
- #include "makelist.h"
-
- main() {
- void *list,*dp,*ptr;
-
- printf("Exercising malloclist...\n");
- list = makelist(sizeof(void *),10);
-
- ptr = "string #1";
- dp = malloclist(list,strlen(ptr)+1);
- strcpy(dp,ptr);
- ptr = "string #2";
- dp = malloclist(list,strlen(ptr)+1);
- strcpy(dp,ptr);
- ptr = "string #3";
- dp = malloclist(list,strlen(ptr)+1);
- strcpy(dp,ptr);
- /* play back list */
- while (dp = walklist(list))
- printf("%s\n",*(char **)dp);
- /* free up the list */
- gclist(list);
- }
-
-
- Example 5: Pushing and poping a list
-
- #ifdef Explanation
- ----------------------------------------------------------------------
- Demonstrate how to push & pop data off of a list.
- ----------------------------------------------------------------------
- #endif
-
- #include <stdio.h>
- #include "makelist.h"
-
- main() {
- void *list,*dp,*ptr;
- int ii,jj,kk;
- int cnt;
-
- /* build list to hold integers */
- list = makelist(sizeof(int),5);
- /* push 10 integers onto list */
- for (ii=0 ; ii < 10 ; ii++)
- pushlist(list,&ii);
- /* walk down list 10 times, popping an entry each time */
- for (ii=0 ; ii < 10 ; ii++) {
- extern void *toplist();
- while (dp = walklist(list))
- printf("%d\n",*(int *)dp);
- dp = toplist(list);
- printf("popping off %d\n",*(int *)dp);
- poplist(list);
- }
- /* list is now empty */
- printf("pushing onto list again\n");
- for (ii=0 ; ii < 10 ; ii++)
- pushlist(list,&ii);
- /* veryify entire list */
- while (dp = walklist(list))
- printf("%d\n",*(int *)dp);
- /* pop off an item at a time off list */
- for (ii=0 ; ii < 10 ; ii++) {
- extern void *toplist();
- dp = toplist(list);
- printf("popping off %d\n",*(int *)dp);
- poplist(list);
- }
- /* ensure list is indeed empty */
- printf("walking list again... should be empty\n");
- while (dp = walklist(list))
- printf("%d\n",*(int *)dp);
- freelist(list);
- }
-
-
- Example 6: Property list usage
-
-
- #ifdef Explanation
- ----------------------------------------------------------------------
- Put 100 integers on a list. Every 5th element on the list, add a
- special property value.
- ----------------------------------------------------------------------
- #endif
-
- #include <stdio.h>
- #include "makelist.h"
-
- extern char *strdup();
-
- main() {
- void *list,*dp,*ptr;
- int jj;
- int cnt;
- void *nl = makelist(sizeof(int),20);
-
- for (jj=0 ; jj < 100 ; jj++) {
- void *dp = appendlist(nl,&jj);
- /* every 5th element, put something on property list */
- if (!(jj%5)) {
- char buffer[80];
- sprintf(buffer,"list[%d]",jj);
- putproplist(nl,dp,"MSG",strdup(buffer));
- }
- }
- for (jj=0 ; jj < 100 ; jj++) {
- void *dp = fetchlist(nl,jj);
- char *ptr;
- printf("%d\n",*(int *)dp);
- if (!(jj%5)) {
- void *p = (jj) ? dp : (void *)NULL;
- printf("PROP: %s\n",ptr = getproplist(nl,p,"MSG"));
- free(ptr);
- }
- }
- freelist(nl);
- }
-
-
- Example 7: Property list usage w/pappendlist
-
-
- #ifdef Explanation
- ----------------------------------------------------------------------
- Make a list to hold integers, and put 100 integers onto the list.
- Then, play back the list. For each integer put on the list, add
- a property value which uniquely identifies the data value.
- ----------------------------------------------------------------------
- #endif
-
- #include <stdio.h>
- #include "makelist.h"
-
- extern char *strdup();
-
- main() {
- void *list,*dp;
- char *ptr,buffer[80];
- int ii;
-
- list = makelist(sizeof(int),10);
-
- /* put 100 integers on list, w/ prop to tell their index in ASCII */
- for (ii=0 ; ii < 100 ; ii++) {
- sprintf(buffer,"index %d",ii);
- pappendlist(list,&ii,"OP",strdup(buffer));
- }
- /* get each integer off list, and show its property */
- for (ii=0 ; ii < 100 ; ii++) {
- void *dp = fetchlist(list,ii);
- ptr = getproplist(list,dp,"OP");
- printf("Entry %2d = %d, prop = %s\n",ii,*(int *)dp,ptr);
- free(ptr);
- }
- freelist(list);
- }
-
-
- Example 8: A list of lists
-
-
- #ifdef Explanation
- ----------------------------------------------------------------------
- Build and populate a list of lists
- ----------------------------------------------------------------------
- #endif
-
- #include <stdio.h>
- #include "makelist.h"
-
- main() {
- void *listlist;
- int ii,jj,kk;
-
- /* create a list of lists */
- listlist = makelist(sizeof(void *),10);
- /* build 10 lists to hold integers */
- for (ii=0 ; ii < 10 ; ii++) {
- void *vp = makelist(sizeof(int),10);
- appendlist(listlist,&vp);
- }
- /* populate each of the 10 lists */
- for (ii=0 ; ii < 10 ; ii++) {
- void *list = *(void **)fetchlist(listlist,ii);
- for (jj=0 ; jj < 20 ; jj++) {
- kk = ii*100 + jj;
- appendlist(list,&kk);
- }
- }
- /* replay each of the 10 lists */
- for (ii=0 ; ii < 10 ; ii++) {
- void *list = *(void **)fetchlist(listlist,ii);
- for (jj=0 ; jj < 20 ; jj++)
- printf("List %d, data = %d\n",ii,*(int *)fetchlist(list,jj));
- }
- /* free all lists */
- for (ii=0 ; ii < 10 ; ii++) {
- void *list = *(void **)fetchlist(listlist,ii);
- freelist(list);
- }
- freelist(listlist);
- }
-
-
- Example 9: A list of functions
-
-
- #ifdef Explanation
- ----------------------------------------------------------------------
- Demonstrate how to use build a list of functions and call them
- directly off of the list, with arguments.
- ----------------------------------------------------------------------
- #endif
-
- #include <stdio.h>
- #include <varargs.h>
- #include "makelist.h"
-
- /* This function expects integer arguments, zero terminated */
- static
- foo(argmark)
- va_list argmark; {
- int i;
- while (1) {
- i = va_arg(argmark,int);
- if (!i) break;
- printf("%d\n",i);
- }
- }
-
- /* This function expects string arguments, NULL terminated */
- static
- goo(argmark)
- va_list argmark; {
- char *ptr;
- while (1) {
- ptr = va_arg(argmark,char *);
- if (!ptr) break;
- printf("%s\n",ptr);
- }
- }
-
- /* This function expects a string, followed by an integer */
- static
- poo(argmark)
- va_list argmark; {
- char *ptr;
- int i;
- ptr = va_arg(argmark,char *);
- i = va_arg(argmark,int);
- printf("string = %s, int = %d\n",ptr,i);
- }
-
- /* build list for functions internal to proc, and return pointer to list */
- static void *flist = NULL;
- void *
- f_proc() {
- int (*func)();
- if (!flist) flist = makelist(sizeof(int (*)()),10);
- /* put functions on flist, and give 'em names */
- func = foo; pappendlist(flist,&func,"FOO",NULL);
- func = goo; pappendlist(flist,&func,"GOO",NULL);
- func = poo; pappendlist(flist,&func,"POO",NULL);
- return flist;
- }
-
- /* our proc function */
- void
- proc() {
- printf("In function proc\n");
- }
-
- main() {
- void *l_proc;
- /* get list of proc's functions */
- l_proc = f_proc();
- /* invoke each of the functions with arguments */
- funclist(l_proc,"FOO",1,2,3,4,0);
- funclist(l_proc,"GOO","line 1", "line 2", "line 3", NULL);
- funclist(l_proc,"POO","some text", 666);
- /* finally, call proc */
- proc();
- }
-
-
-